﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Aribaccio
{
    /// <summary>
    /// 简单混合锁(简单混合线程同步锁，采用了基元用户加基元内核同步构造实现)
    /// </summary>
    public class SimpleHybirdLock : IDisposable
    {
        /// <summary>
        /// 基元用户模式构造同步锁
        /// </summary>
        private int waiters = 0;
        /// <summary>
        /// 要检测冗余调用
        /// </summary>
        private bool DisposedValue { get; set; }
        /// <summary>
        /// 基元内核模式构造同步锁
        /// </summary>
        private AutoResetEvent WaiterLock { get; set; }
        /// <summary>
        /// 获取当前锁是否在等待当中
        /// </summary>
        public bool IsWaitting { get { return waiters != 0; } }

        /// <summary>
        /// 构造函数
        /// </summary>
        public SimpleHybirdLock()
        {
            this.DisposedValue = false;
            this.waiters = 0;
            this.WaiterLock = new AutoResetEvent(false);
        }

        /// <summary>
        /// 获取锁
        /// </summary>
        public void Enter()
        {
            ////用户锁可以使用的时候，直接返回，第一次调用时发生
            if (Interlocked.Increment(ref waiters) == 1) { return; }
            //当发生锁竞争时，使用内核同步构造锁
            this.WaiterLock.WaitOne();
        }

        /// <summary>
        /// 离开锁
        /// </summary>
        public void Leave()
        {
            //没有可用的锁的时候
            if (Interlocked.Decrement(ref waiters) == 0) { return; }
            this.WaiterLock.Set();
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            this.Dispose(true);
            // TODO: 如果在以上内容中替代了终结器，则取消注释以下行。
            // GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="argDisposing"></param>
        public void Dispose(bool argDisposing)
        {
            if (!DisposedValue)
            {
                if (argDisposing)
                {
                    // TODO: 释放托管状态(托管对象)。
                }
                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。
                this.WaiterLock.Close();
                this.DisposedValue = true;
            }
        }
    }
}
